package com.example.walkera.firstexoplayerdemo;

import android.content.Context;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;

import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Timeline;

import java.util.Formatter;
import java.util.Locale;

/**
 * Created by kaifa@lihaiping1603 on 2016/11/23.
 * 仿写一个playbackcontrollerview，用于做媒体播放控制用
 * 只带一个进度条的meddiacontrollerview
 */
public class AVPlayerSimpleControllerView extends LinearLayout{
    /**
     * Listener to be notified about changes of the visibility of the UI control.
     */
    public interface VisibilityListener {
        /**
         * Called when the visibility changes.
         *
         * @param visibility The new visibility. Either {@link View#VISIBLE} or {@link View#GONE}.
         */
        void onVisibilityChange(int visibility);
    }
    //定义公共变量
    public static final int DEFAULT_SHOW_TIMEOUT_MS = 5000;

    //定义类内部变量
    private final String TAG="AVExoPlayerControllerView";

    private static final int MEDIA_PROGRESS_BAR_MAX = 1000;


    private final TextView mediaTimeCurrent;
    private final SeekBar  mediaProgressBar;
    private final TextView mediaTimeTotal;
    private final ComponentListener mediaComponentListener;
    private ExoPlayer mediaExoPlayer;
    private VisibilityListener visibilityListener;
    private int showTimeoutMs;
    private long hideAtMs;
    private boolean bAttachedToWindow;
    private boolean bDragging;
    private final StringBuilder formatBuilder;
    private final Formatter formatter;

    private final Runnable updateProgressAction = new Runnable() {
        @Override
        public void run() {
            updateProgress();
        }
    };

    private final Runnable hideAction = new Runnable() {
        @Override
        public void run() {
            hide();
        }
    };

    public AVPlayerSimpleControllerView(Context context){
        this(context,null);
    }
    public AVPlayerSimpleControllerView(Context context, AttributeSet attrs){
        this(context,attrs,0);
    }

    public AVPlayerSimpleControllerView(Context context, AttributeSet attrs, int defStyleAttr){
        super(context,attrs,defStyleAttr);

        //加载一个布局
        LayoutInflater.from(context).inflate(R.layout.avplayer_simple_controller_view,this);

        mediaTimeCurrent=(TextView)findViewById(R.id.avplayer_sc_currrenttime);
        mediaProgressBar=(SeekBar)findViewById(R.id.avplyer_sc_progress);
        mediaTimeTotal=(TextView)findViewById(R.id.avplayer_sc_totaltime);

        mediaComponentListener = new ComponentListener();
        mediaProgressBar.setMax(MEDIA_PROGRESS_BAR_MAX);
        mediaProgressBar.setOnSeekBarChangeListener(mediaComponentListener);

        formatBuilder = new StringBuilder();
        formatter = new Formatter(formatBuilder, Locale.getDefault());
    }

    /**
     * Returns the player currently being controlled by this view, or null if no player is set.
     */
    public ExoPlayer getPlayer() {
        return mediaExoPlayer;
    }

    /**
     * Sets the {@link ExoPlayer} to control.
     *
     * @param player the {@code ExoPlayer} to control.
     */
    public void setPlayer(ExoPlayer player) {
        if (this.mediaExoPlayer == player) {
            return;
        }
        if (this.mediaExoPlayer != null) {
            this.mediaExoPlayer.removeListener(mediaComponentListener);
        }
        this.mediaExoPlayer = player;
        if (player != null) {
            player.addListener(mediaComponentListener);
        }
        updateAll();
    }

    /**
     * Sets the {@link VisibilityListener}.
     *
     * @param listener The listener to be notified about visibility changes.
     */
    public void setVisibilityListener(VisibilityListener listener) {
        this.visibilityListener = listener;
    }

    /**
     * Returns the playback controls timeout. The playback controls are automatically hidden after
     * this duration of time has elapsed without user input.
     *
     * @return The duration in milliseconds. A non-positive value indicates that the controls will
     *     remain visible indefinitely.
     */
    public int getShowTimeoutMs() {
        return showTimeoutMs;
    }

    /**
     * Sets the playback controls timeout. The playback controls are automatically hidden after this
     * duration of time has elapsed without user input.
     *
     * @param showTimeoutMs The duration in milliseconds. A non-positive value will cause the controls
     *     to remain visible indefinitely.
     */
    public void setShowTimeoutMs(int showTimeoutMs) {
        this.showTimeoutMs = showTimeoutMs;
    }

    /**
     * Shows the playback controls. If {@link #getShowTimeoutMs()} is positive then the controls will
     * be automatically hidden after this duration of time has elapsed without user input.
     */
    public void show() {
        if (!isVisible()) {
            setVisibility(VISIBLE);
            if (visibilityListener != null) {
                visibilityListener.onVisibilityChange(getVisibility());
            }
            updateAll();
        }
        // Call hideAfterTimeout even if already visible to reset the timeout.
        hideAfterTimeout();
    }

    /**
     * Hides the controller.
     */
    public void hide() {
        if (isVisible()) {
            setVisibility(GONE);
            if (visibilityListener != null) {
                visibilityListener.onVisibilityChange(getVisibility());
            }
            removeCallbacks(updateProgressAction);
            removeCallbacks(hideAction);
            hideAtMs = C.TIME_UNSET;
        }
    }

    /**
     * Returns whether the controller is currently visible.
     */
    public boolean isVisible() {
        return getVisibility() == VISIBLE;
    }

    private void hideAfterTimeout() {
        removeCallbacks(hideAction);
        if (showTimeoutMs > 0) {
            hideAtMs = SystemClock.uptimeMillis() + showTimeoutMs;
            if (bAttachedToWindow) {
                postDelayed(hideAction, showTimeoutMs);
            }
        } else {
            hideAtMs = C.TIME_UNSET;
        }
    }

    private void updateAll() {
        updateProgress();
    }


    private void updateProgress() {
        if (!isVisible() || !bAttachedToWindow) {
            return;
        }
        long duration = mediaExoPlayer == null ? 0 : mediaExoPlayer.getDuration();
        long position = mediaExoPlayer == null ? 0 : mediaExoPlayer.getCurrentPosition();
        mediaTimeTotal.setText(stringForTime(duration));
        if (!bDragging) {
            mediaTimeCurrent.setText(stringForTime(position));
        }
        if (!bDragging) {
            mediaProgressBar.setProgress(progressBarValue(position));
        }
        long bufferedPosition = mediaExoPlayer == null ? 0 : mediaExoPlayer.getBufferedPosition();
        mediaProgressBar.setSecondaryProgress(progressBarValue(bufferedPosition));
        // Remove scheduled updates.
        removeCallbacks(updateProgressAction);
        // Schedule an update if necessary.
        int playbackState = mediaExoPlayer == null ? ExoPlayer.STATE_IDLE : mediaExoPlayer.getPlaybackState();
        if (playbackState != ExoPlayer.STATE_IDLE && playbackState != ExoPlayer.STATE_ENDED) {
            long delayMs;
            if (mediaExoPlayer.getPlayWhenReady() && playbackState == ExoPlayer.STATE_READY) {
                delayMs = 1000 - (position % 1000);
                if (delayMs < 200) {
                    delayMs += 1000;
                }
            } else {
                delayMs = 1000;
            }
            postDelayed(updateProgressAction, delayMs);
        }
    }

    private String stringForTime(long timeMs) {
        if (timeMs == C.TIME_UNSET) {
            timeMs = 0;
        }
        long totalSeconds = (timeMs + 500) / 1000;
        long seconds = totalSeconds % 60;
        long minutes = (totalSeconds / 60) % 60;
        long hours = totalSeconds / 3600;
        formatBuilder.setLength(0);
        return hours > 0 ? formatter.format("%d:%02d:%02d", hours, minutes, seconds).toString()
                : formatter.format("%02d:%02d", minutes, seconds).toString();
    }

    private int progressBarValue(long position) {
        long duration = mediaExoPlayer == null ? C.TIME_UNSET : mediaExoPlayer.getDuration();
        return duration == C.TIME_UNSET || duration == 0 ? 0
                : (int) ((position * MEDIA_PROGRESS_BAR_MAX) / duration);
    }

    private long positionValue(int progress) {
        long duration = mediaExoPlayer == null ? C.TIME_UNSET : mediaExoPlayer.getDuration();
        return duration == C.TIME_UNSET ? 0 : ((duration * progress) / MEDIA_PROGRESS_BAR_MAX);
    }


    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        bAttachedToWindow = true;
        if (hideAtMs != C.TIME_UNSET) {
            long delayMs = hideAtMs - SystemClock.uptimeMillis();
            if (delayMs <= 0) {
                hide();
            } else {
                postDelayed(hideAction, delayMs);
            }
        }
        updateAll();
    }

    @Override
    public void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        bAttachedToWindow = false;
        removeCallbacks(updateProgressAction);
        removeCallbacks(hideAction);
    }

    /////////////////////////////////////////////////////////////////////

    private final class ComponentListener implements ExoPlayer.EventListener, SeekBar.OnSeekBarChangeListener {

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
            removeCallbacks(hideAction);
            bDragging = true;
        }

        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            if (fromUser) {
                mediaTimeCurrent.setText(stringForTime(positionValue(progress)));
            }
        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            bDragging = false;
            mediaExoPlayer.seekTo(positionValue(seekBar.getProgress()));
            hideAfterTimeout();
        }

        @Override
        public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
            updateProgress();
        }

        @Override
        public void onPositionDiscontinuity() {
            updateProgress();
        }

        @Override
        public void onTimelineChanged(Timeline timeline, Object manifest) {
            updateProgress();
        }

        @Override
        public void onLoadingChanged(boolean isLoading) {
            // Do nothing.
        }

        @Override
        public void onPlayerError(ExoPlaybackException error) {
            // Do nothing.
        }
    }
}
